#include "InputHandler.h"
#include "GameHandler.h"
#include <iterator>
#include <cstdio> 


InputHandler* InputHandler::s_pInstance = nullptr; 


const Uint8* InputHandler::m_keystate(SDL_GetKeyboardState(0)); 


void InputHandler::initJoy() 
{
	if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
	{
		SDL_InitSubSystem(SDL_INIT_JOYSTICK); 
	}

	if (SDL_NumJoysticks() > 0)
	{
		for (int i = 0; i < SDL_NumJoysticks(); ++i)
		{
			SDL_Joystick* joy = SDL_JoystickOpen(i); 
			
			if (SDL_JoystickGetAttached(joy) == SDL_TRUE)
			{
				m_joysticks.push_back(joy); 
				m_joystickValues.push_back(std::make_pair(new Vector2D, new Vector2D)); 

				std::vector <unsigned char> temp;

				for (int j = 0; j < SDL_JoystickNumButtons(joy); ++j)
					temp.push_back(false); 

				m_joyButtonStates.push_back(temp);
			}

			else 
			{
				printf("%s", SDL_GetError()); 
			}
		}

			SDL_JoystickEventState(SDL_ENABLE);
			m_bJoyInit = true; 

		}

	else 
	{
		m_bJoyInit = false; 
	}
}


void InputHandler::initMouse()
{
	for (size_t i = 0; i < 3; ++i)
		m_mouseButtonStates[i] = false; 
}


void InputHandler::Update()
{
	// Main event handler
	SDL_Event ev; 
	
	while (SDL_PollEvent(&ev))
	{
		switch (ev.type)
		{
			case SDL_QUIT: 
				GameHandler::Instance() -> Quit();
				break;
			
			case SDL_JOYAXISMOTION: 
				onJoystickAxisMove(ev); 
				break;
			
			case SDL_JOYBUTTONDOWN:
				onJoystickButtonDown(ev); 
				break; 

			case SDL_MOUSEMOTION: 
				onMouseMove(ev);
				break; 

			case SDL_JOYBUTTONUP:
				onJoystickButtonUp(ev); 
				break;

			case SDL_MOUSEBUTTONDOWN: 
				onMouseButtonDown(ev);
				break; 

			case SDL_MOUSEBUTTONUP: 
				onMouseButtonUp(ev);
				break;

			default: 
				break; 
		}
	}
}


void InputHandler::CleanUp()
{
	if (m_bJoyInit)
	{
		for (int i = 0; i < SDL_NumJoysticks(); ++i)
		{
			SDL_JoystickClose(m_joysticks[i]); 
		}

		typedef std::vector <std::pair<Vector2D*, Vector2D*> >::iterator Iter; 

		for (Iter it =  m_joystickValues.begin(); it != m_joystickValues.end(); ++it)
		{
			delete it -> first; 
			delete it -> second; 
		}
	}
}


float InputHandler::xAxis(int joy, int stick) const 
{
	if (m_joystickValues.size() > 0)
	{
		if (stick == 1) 
			return m_joystickValues[joy].first -> x; 

		else if (stick == 2)
		    return m_joystickValues[joy].second -> x; 
	}

	return 0; 
}


float InputHandler::yAxis(int joy, int stick) const 
{
	if (m_joystickValues.size() > 0)
	{
		if (stick == 1) 
			return m_joystickValues[joy].first -> y; 

		else if (stick == 2)
		    return m_joystickValues[joy].second -> y; 
	}

	return 0; 
}


// Make the statement explicit for warning C4800 (performance warning)
bool InputHandler::joyButtonState(int joy, int bindex) const 
{
	return m_joyButtonStates[joy][bindex] == 1;
}


bool InputHandler::mouseButtonState(int bindex) const 
{
	return m_mouseButtonStates[bindex]; 
}


bool InputHandler::isKeyDown(SDL_Scancode key)
{
	if (m_keystate != nullptr)
	{
	    return (m_keystate[key] == 1) ? true : false;
	}

	return false; 
}


void InputHandler::onMouseMove(SDL_Event& ev)
{
	m_mousePosition.x = static_cast <float> (ev.motion.x); 
	m_mousePosition.y = static_cast <float> (ev.motion.y);
}


void InputHandler::onMouseButtonDown(SDL_Event& ev)
{
	if (ev.button.button == SDL_BUTTON_LEFT)
		m_mouseButtonStates[LEFT] = true; 

	if (ev.button.button == SDL_BUTTON_MIDDLE)
		m_mouseButtonStates[MIDDLE] = true; 

	if (ev.button.button == SDL_BUTTON_RIGHT)
		m_mouseButtonStates[RIGHT] = true; 
}


void InputHandler::onMouseButtonUp(SDL_Event& ev)
{
	if (ev.button.button == SDL_BUTTON_LEFT)
		m_mouseButtonStates[LEFT] = false; 

	if (ev.button.button == SDL_BUTTON_MIDDLE)
		m_mouseButtonStates[MIDDLE] = false; 

	if (ev.button.button == SDL_BUTTON_RIGHT)
		m_mouseButtonStates[RIGHT] = false; 
}


void InputHandler::onJoystickAxisMove(SDL_Event& ev) 
{
	// Account for the controller's sensitivity
	static const int joy_dead_zone = 10000;  

    // Check from which controller is it 
	static int which = ev.jaxis.which; 
	
	if (ev.jaxis.axis == 0) 
	{
		if (ev.jaxis.value > joy_dead_zone)
			m_joystickValues[which].first -> x = 1; 

		else if (ev.jaxis.value < -joy_dead_zone)
			m_joystickValues[which].first -> x = -1;

		else 
			m_joystickValues[which].first -> x = 0; 
					}
		if (ev.jaxis.axis == 1) 
		{
			if (ev.jaxis.value > joy_dead_zone)
				m_joystickValues[which].first -> y = 1; 

			else if (ev.jaxis.value < -joy_dead_zone)
				m_joystickValues[which].first -> y = -1;

			else 
				m_joystickValues[which].first -> y = 0; 
		}

		if (ev.jaxis.axis == 3) 
		{
			if (ev.jaxis.value > joy_dead_zone)
				m_joystickValues[which].second -> x = 1; 

			else if (ev.jaxis.value < -joy_dead_zone)
				m_joystickValues[which].second -> x = -1;

			else 
				m_joystickValues[which].second -> x = 0; 
		}

		if (ev.jaxis.axis == 4) 
		{
			if (ev.jaxis.value > joy_dead_zone)
				m_joystickValues[which].second -> y = 1; 

			else if (ev.jaxis.value < -joy_dead_zone)
				m_joystickValues[which].second -> y = -1;

			else 
				m_joystickValues[which].second -> y = 0; 
		}
}


void InputHandler::onJoystickButtonDown(SDL_Event& ev)
{
	int which = ev.jaxis.which; 

	m_joyButtonStates[which][ev.jbutton.button] = true; 
}


void InputHandler::onJoystickButtonUp(SDL_Event& ev)
{
	int which = ev.jaxis.which; 

	m_joyButtonStates[which][ev.jbutton.button] = false; 
}

